import angular = require("angular");
import {ComponentFactory} from"./component-factory";
import {Cache} from "./util/cache";
import {Component, Bridge, Layout} from "./component";

export interface Reister{
    register(factory: ComponentFactory<Component>):void;
    registerLayout(factory: ComponentFactory<Layout>):void;
}

export default class FormStudio implements Reister{

    private componentMap : Cache;
    private layoutMap: Cache;
    private $compile: angular.ICompileService;
    private $rootScope: angular.IScope;

    private rootLayout: Layout;

    constructor(){
        this.componentMap = new Cache();
        this.layoutMap = new Cache();
    }

    init($compile, $rootScope, layout: Layout):void{
        if(this.rootLayout != null){
            throw new Error("rootLayout has bean config");
        }
        this.$rootScope = $rootScope;
        this.$compile = $compile;
        this.rootLayout =layout;
    }

    addComponent(component: Component): void{
        this.rootLayout.addComponent(component);
    }

    removeComponent(component: Component):void{
        this.rootLayout.removeComponent(component);
    }

    register(factory: ComponentFactory<Component>): void{
        if(factory)
            this.componentMap.put(factory.componentKey, factory);
    }

    registerLayout(factory: ComponentFactory<Layout>): void{
        if(factory)
            this.layoutMap.put(factory.componentKey, factory);
    }

    getComponnets(): any{
        return this.componentMap.values();
    }

    getLayouts(): any{
        return this.layoutMap.values();
    }

    getComponentOrLayout(componentKey:string):ComponentFactory<Component> | ComponentFactory<Layout>{
        let component = this.getComponent(componentKey);
        if(!component){
            component = this.getLayout(componentKey);
        }
        return component;
    }

    getComponent(componentKey: string): ComponentFactory<Component>{
        return this.componentMap.get(componentKey);
    }

    getLayout(componentKey:string): ComponentFactory<Layout>{
        return this.layoutMap.get(componentKey);
    }

    /**
     * 连接组件属性模板和组件实例
     * @param {Component} component
     * @param {string} propTpl
     * @returns {JQLite}
     */
    connect(component: Component, propTpl:string): JQLite{
       let scope =  this.$rootScope.$new();
       let bindScope = this.$compile(propTpl);
       scope['componentProps'] = component.componentProps;

       return bindScope(scope);
    }

    /**
     * 生成一个桥接器
     * @param component
     * @param propTpl
     */
    populateBridge(component: Component, propTpl:string):void{
        let scope =  this.$rootScope.$new();
        let bindScope = this.$compile(propTpl);
        scope['componentProps'] = component.componentProps;

        let jq = bindScope(scope);
        component.init(new Bridge(scope, jq));
    }

    /**
     * 提取组件实例
     * @param dom
     */
    extractComponent(dom: JQLite): Component{
        return dom.data('component');
    }

    storeComponent(dom: JQLite, component:Component){
        if(!component.bridge.is(dom)){
            throw new Error("dom must be same of Component.template");
        }
        dom.data('component', component);
    }
}
